package com.sh.data.engine.domain.normalization.standard.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.sh.data.engine.common.constants.HttpStatus;
import com.sh.data.engine.common.constants.code.BizCodes;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.exception.InvalidParamException;
import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.common.service.CommonService;
import com.sh.data.engine.domain.dataasset.service.TblPropService;
import com.sh.data.engine.domain.normalization.standard.model.domain.DictionaryDetailDomain;
import com.sh.data.engine.domain.normalization.standard.model.domain.DictionaryMappingDetailDomain;
import com.sh.data.engine.domain.normalization.standard.model.mapper.DictionaryMappingDetailDomainMapper;
import com.sh.data.engine.domain.normalization.standard.model.mapper.DictionaryMappingDetailEntityMapper;
import com.sh.data.engine.domain.normalization.standard.model.param.DictionaryMappingDetailParam;
import com.sh.data.engine.domain.normalization.standard.model.param.MappingDetailParam;
import com.sh.data.engine.domain.normalization.standard.service.IDictionaryMappingDetailService;
import com.sh.data.engine.domain.normalization.standard.service.IDictionaryService;
import com.sh.data.engine.domain.shims.db.BaseDbManager;
import com.sh.data.engine.domain.shims.db.model.FieldInfoDomain;
import com.sh.data.engine.domain.shims.db.model.TableInfoDomain;
import com.sh.data.engine.domain.shims.sql.builder.DDLBuilder;
import com.sh.data.engine.domain.shims.sql.ddl.EditTableFieldParam;
import com.sh.data.engine.repository.dao.dataasset.entity.TblPropEntity;
import com.sh.data.engine.repository.dao.normalization.standard.DictionaryMappingDetailMapper;
import com.sh.data.engine.repository.dao.normalization.standard.entity.DictionaryMappingDetailEntity;
import com.sh.data.engine.repository.dao.workspace.manager.entity.StorageEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author jingchen.hr
 */
@Service
@Slf4j
public class DictionaryMappingDetailServiceImpl
    extends ServiceImpl<DictionaryMappingDetailMapper, DictionaryMappingDetailEntity>
    implements IDictionaryMappingDetailService {

    @Autowired
    private DictionaryMappingDetailMapper dictionaryMappingDetailMapper;

    @Autowired
    private IDictionaryService dictionaryServiceImpl;

//    @Autowired
//    private ProjectService projectService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private TblPropService tblPropService;

    @Autowired
    private DictionaryMappingDetailDomainMapper dictionaryMappingDetailDomainMapper;

    @Autowired
    private DictionaryMappingDetailEntityMapper dictionaryMappingDetailEntityMapper;

    @Override
    public List<DictionaryMappingDetailEntity> queryList(Long dictId, Integer mapSource) {
        if (dictId == null) {
            return Lists.newArrayList();
        }
        return dictionaryMappingDetailMapper.queryList(dictId, mapSource);
    }

    @Transactional(rollbackFor = Exception.class, transactionManager = "engineTransactionManager")
    @Override
    public DictionaryMappingDetailEntity detailBound(MappingDetailParam param) {
        DictionaryMappingDetailEntity dictionaryMappingDetailEntity = queryById(param.getId());
        if (Objects.equals(dictionaryMappingDetailEntity.getBoundStatus(), param.getBoundStatus())) {
            return dictionaryMappingDetailEntity;
        }

        DictionaryMappingDetailEntity update = new DictionaryMappingDetailEntity();
        update.setId(param.getId());
        update.setUpdaterId(UserContext.getUserId());
        update.setBoundStatus(param.getBoundStatus());
        update.setUpdateTime(new Date());
        dictionaryMappingDetailMapper.updateById(update);
        return dictionaryMappingDetailEntity;
    }

    private DictionaryMappingDetailEntity queryById(Long id) {
        DictionaryMappingDetailEntity dictionaryMappingDetailEntity =
            dictionaryMappingDetailMapper.getById(id);
        if (dictionaryMappingDetailEntity == null) {
            throw new BusinessException(BizCodes.DICTIONARY_MAPPING_DETAIL_NOT_FOUND_ERROR, HttpStatus.BAD_REQUEST);
        }
        return dictionaryMappingDetailEntity;
    }

    @Override
    public void detailMaintain(MappingDetailParam param) {
        DictionaryMappingDetailEntity dictionaryMappingDetailEntity = queryById(param.getId());
        DictionaryDetailDomain dictionaryDetailDomain =
            dictionaryServiceImpl.detailDictionary(dictionaryMappingDetailEntity.getDictId());
        if (Objects.isNull(dictionaryDetailDomain)) {
            return;
        }
        var projectId = ServletUtils.getProjectId();
        TblPropEntity tblProp =
            tblPropService.getTblPropByTblId(
                projectId, dictionaryMappingDetailEntity.getTblId());

        modifyTableFieldComment(
            tblProp.getTableName(),
            dictionaryMappingDetailEntity.getFieldName(),
            dictionaryDetailDomain.getDictNameCn());

        DictionaryMappingDetailEntity update = new DictionaryMappingDetailEntity();
        update.setId(dictionaryMappingDetailEntity.getId());
        update.setFieldDes(dictionaryDetailDomain.getDictNameCn());
        update.setUpdateTime(new Date());
        dictionaryMappingDetailMapper.updateById(update);
    }

    @Override
    public List<DictionaryMappingDetailDomain> getListByTblId(Long tblId) {
        return dictionaryMappingDetailDomainMapper.map(dictionaryMappingDetailMapper.getListByTblTd(tblId));
    }

    @Override
    public List<DictionaryMappingDetailDomain> getByDicMappingId(Long dicMappingId) {
        LambdaQueryWrapper<DictionaryMappingDetailEntity> query =
            new QueryWrapper<DictionaryMappingDetailEntity>().lambda();
        query.eq(DictionaryMappingDetailEntity::getDictMappingId, dicMappingId);

        return dictionaryMappingDetailDomainMapper.map(dictionaryMappingDetailMapper.selectList(query));
    }

    private void modifyTableFieldComment(String tblName, String fieldName, String fieldDes) {
        if (StringUtils.isBlank(fieldName)) {
            throw new InvalidParamException("字段不正确");
        }

        var projectId = ServletUtils.getProjectId();
//        ProjectEntity project = projectService.getProjectById(projectId);

        // long tableId = Long.parseLong(tblId);

        BaseDbManager dbManager = commonService.getStorageDbManagerByProjctId(projectId);
        StorageEntity storage = commonService.getStorage(projectId);
        TableInfoDomain tableInfoDomain = null;
        String dbName =
            StringUtils.isNotBlank(storage.getRmdbs().getSchema())
                ? storage.getRmdbs().getSchema()
                : storage.getRmdbs().getDbName();
        try {
            tableInfoDomain = dbManager.getTableInfoByTableName(dbName, tblName);
        } catch (SQLException ignored) {

        }
        if (tableInfoDomain == null) {
            throw new InvalidParamException("所需维护的表不存在");
        }

        List<FieldInfoDomain> tableFieldList = null;
        try {
            tableFieldList = dbManager.getFieldList(dbName, tableInfoDomain.getTableName());
        } catch (SQLException ignored) {

        }
        if (tableFieldList == null || tableFieldList.size() == 0) {
            throw new InvalidParamException("所需维护的字段不存在");
        }
        Map<String, FieldInfoDomain> fieldNameMap =
            tableFieldList.stream().collect(Collectors.toMap(FieldInfoDomain::getFieldName, o -> o));
        FieldInfoDomain fieldInfoDomain = fieldNameMap.get(fieldName);

        if (fieldInfoDomain == null) {
            throw new InvalidParamException("所需维护的字段不存在");
        }

        log.info("修改字段 字段信息:{}", fieldInfoDomain);

        try {
            DDLBuilder ddlBuilder = dbManager.getDDLBuilder();
            EditTableFieldParam editTableFieldParam = new EditTableFieldParam();
            editTableFieldParam.setFieldName(fieldName);
            editTableFieldParam.setComment(fieldDes);
            editTableFieldParam.setNewFieldName(fieldName);
            editTableFieldParam.setFieldType(fieldInfoDomain.getFieldType());
            if ("PostgreSQL".equals(storage.getStorageType())) {
                ddlBuilder
                    .editTableField(
                        storage.getRmdbs().getSchema(),
                        tableInfoDomain.getTableName(),
                        Lists.newArrayList(editTableFieldParam))
                    .execute();
            } else {
                ddlBuilder
                    .editTableField(
                        storage.getRmdbs().getDbName(),
                        tableInfoDomain.getTableName(),
                        Lists.newArrayList(editTableFieldParam))
                    .execute();
            }

        } catch (Exception e) {
            log.error("修改字段 error:", e);
            throw new InvalidParamException("维护失败");
        }
    }

    public int saveDictMappingDetailList(List<DictionaryMappingDetailParam> params) {
        if (CollectionUtils.isEmpty(params)) {
            return 0;
        }
        List<DictionaryMappingDetailEntity> detailEntities = dictionaryMappingDetailEntityMapper.map(params);
        detailEntities.forEach(
            detail -> {
                detail.setCreateTime(new Date());
                detail.setUpdateTime(new Date());
                boolean save = this.save(detail);
                if (!save) {
                    log.error("保存字典映射详细信息失败");
                    throw new BusinessException("保存字典映射详细信息失败");
                }
            });
        return detailEntities.size();
    }

    public int saveDictMappingDetail(DictionaryMappingDetailParam param) {
        if (null == param) {
            return 0;
        }
        DictionaryMappingDetailEntity detailEntitity = dictionaryMappingDetailEntityMapper.map(param);
        detailEntitity.setCreateTime(new Date());
        detailEntitity.setUpdateTime(new Date());
        dictionaryMappingDetailMapper.insert(detailEntitity);
        return 1;
    }

    public int deleteByDictMappingId(Long dictMappingId) {
        if (null == dictMappingId) {
            return 0;
        }
        LambdaQueryWrapper<DictionaryMappingDetailEntity> query =
            new QueryWrapper<DictionaryMappingDetailEntity>().lambda();
        query.eq(DictionaryMappingDetailEntity::getDictMappingId, dictMappingId);
        return dictionaryMappingDetailMapper.delete(query);
    }

    public List<DictionaryMappingDetailDomain> getDetailByProjectAndMppingId(
        Long projectId, Long dictMappingId, Long tblId) {
        List<DictionaryMappingDetailEntity> details =
            dictionaryMappingDetailMapper.getDetailByProjectAndMppingId(
                projectId, dictMappingId, tblId);
        return dictionaryMappingDetailDomainMapper.map(details);
    }

    public int updateById(DictionaryMappingDetailParam param) {
        if (null != param) {
            DictionaryMappingDetailEntity dictionaryMappingDetailEntity = dictionaryMappingDetailEntityMapper.map(param);
            dictionaryMappingDetailEntity.setUpdateTime(new Date());

            return dictionaryMappingDetailMapper.updateById(dictionaryMappingDetailEntity);
        }
        return 0;
    }

    public int deleteByPrimaryKey(Long id) {
        if (null != id) {
            dictionaryMappingDetailMapper.deleteById(id);
            return 1;
        }
        return 0;
    }

    public int deleteByIds(List<Long> ids) {

        return dictionaryMappingDetailMapper.deleteByIds(ids);
    }

    public int deleteDetailByMapsource(Long projectId, Integer mapsource) {

        LambdaQueryWrapper<DictionaryMappingDetailEntity> query =
            new QueryWrapper<DictionaryMappingDetailEntity>().lambda();
        query
            .eq(DictionaryMappingDetailEntity::getProjectId, projectId)
            .eq(DictionaryMappingDetailEntity::getMapSource, mapsource);
        return dictionaryMappingDetailMapper.delete(query);
    }

    public List<DictionaryMappingDetailDomain> getDetailByProjectAndMppingId(List<Long> tblIds) {
        List<DictionaryMappingDetailEntity> details =
            dictionaryMappingDetailMapper.getDetailByTblIds(tblIds);
        return dictionaryMappingDetailDomainMapper.map(details);
    }
}
